(* C definitions *)
open Ast ;;
open Printf;;

type cty = string

type clval =
| CId of string
(*| CArr of cexp * cexp*)
| CField of cexp * string
 and 
 cexp = 
| CStringConst of string
| CNum of int
| CLval of  clval
| CCast of cty * cexp
| CBinop of binop * cexp * cexp
(*| CMinus of cexp * cexp
| CMul of cexp * cexp
| CDiv of cexp * cexp *)
|CDot of cexp * string
|CApp of cexp * cexp list

type cstm = 
 | CAssign of clval * cexp
 | CReturn of cexp
 | CLocalD of string


type cdecl = 
| VarD of string * cty
| CFunDecl of string * cty * (string * cty) list * cstm list

(* function that converts ocaml AST to C AST  *)

let counter =  ref 0 ;;
let new_id() = 
counter :=  !counter+1;
"temp_" ^ string_of_int(!counter);;


let rec  convert e =
match e with
| Binop ( b, e1, e2) -> let (e1, s1, d1) = convert e1 in
                   let (e2, s2, d2) = convert e2 in
                   (CCast( "val", CBinop (b, CDot (e1, "i"), CDot(e2, "i"))), s1@s2, d1@d2)
| StringConst(s) -> (CStringConst(s), [], [])
| IntConst(i) -> (CNum(i), [], [])
| Var(s) -> (CLval(CId(s)), [] , [VarD(s, "val")])
| Fun(s,e) -> let (e',s',d) = convert e in
              let f = new_id() in
              (CLval(CId(f)), s', (CFunDecl( f, "val", [(s,"val")], [(CReturn e')]))::d)
| App(e1, e2) -> let (e1, s1, d1 ) =  convert e1 in 
                 let (e2, s2, d2)  = convert e2 in 
                 ( CApp(e1,[e2]), s1@s2, d1@d2)
(*in convert (Binop (Plus, StringConst ("a"), StringConst("b")))*)
;;

let gen_def_code_open =
" typedef union val_t { \n int i; \n void* p; \n } val; \n " ^
" typedef struct fun_t { \n val(*f) (val, val *); \n val* env; \n } fun; \n" ^ 
" struct fun_t foo; \n" ^
" return (union val_t) foo; " ^
(* MAIN *)
" int main (int argc, char ** argv) { \n" ^
;

let gen_def_code_close ret =
" return %s \n }" ret;


let rec print_lval l =
match l with
| CId(s) -> printf "%s" s
| CField(field_exp ,b) -> printf "%s.%s"  (print field_exp)  b
and
 print e =
match e with 
| CStringConst(s) -> printf "%s" s
| CNum(i) -> printf "%i" i
| CLval(l) -> print_lval l
| CCast (typ, exp) -> printf "(%s) %s" typ (print exp)
| CBinop( b, e1, e2) -> printf " %s %s %s" (print e1) (print_binop b) (print e2)
| CDot (a, b) -> printf "%s.%s" (print a) b
| CApp of cexp * cexp list



